﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;

namespace comdiinfo
{
    public class G64DiskImage
    {
        private G64ImageData g64ImageData;                          // Data of Image File
        public G64FileSignature g64FileSignature { get; set; }      // "GCR-1541"
        public G64Version g64Version { get; set; }                  // presently only $00 defined
        public G64NumberOfTracks g64NumberOfTracks { get; set; }    // usually $54, decimal 84
        public G64SizeOfTracks g64SizeOfTracks { get; set; }        // usually  7928,  or $1EF8 in LO/HI format.
        public List<G64Track> g64Tracks { get; set; }
        public G64DiskImage(byte[] dataBuffer)
        {
            this.g64ImageData = new G64ImageData(dataBuffer);
            this.g64FileSignature = new G64FileSignature(0);
            this.g64Version = new G64Version(0);
            this.g64NumberOfTracks = new G64NumberOfTracks(0);
            this.g64SizeOfTracks = new G64SizeOfTracks(0);

            this.g64FileSignature.LoadData(ref this.g64ImageData, 0, 8);
            this.g64Version.LoadData(ref this.g64ImageData, 8, 1);
            this.g64NumberOfTracks.LoadData(ref this.g64ImageData, 9, 1);
            this.g64SizeOfTracks.LoadData(ref this.g64ImageData, 10, 2);

            this.g64Tracks = new List<G64Track>();
            for (int trackNo = 1; trackNo <= this.g64NumberOfTracks.ElementValue; trackNo++)
            {
                G64Track track = new G64Track();
                track.LoadData(ref g64ImageData, trackNo, g64NumberOfTracks, g64SizeOfTracks);
                this.g64Tracks.Add(track);
            }
        }
        public String ShowInfo2(String fileName)
        {
            int warningCount = 0;
            int errorCount = 0;
            StringBuilder retText = new StringBuilder();
            StringBuilder errorText = new StringBuilder();
            StringBuilder warningText = new StringBuilder();
            g64FileSignature.SetStatusText(ref warningText, ref warningCount, ref errorText, ref errorCount);
            g64Version.SetStatusText(ref warningText, ref warningCount, ref errorText, ref errorCount);
            g64NumberOfTracks.SetStatusText(ref warningText, ref warningCount, ref errorText, ref errorCount);
            g64SizeOfTracks.SetStatusText(ref warningText, ref warningCount, ref errorText, ref errorCount);

            foreach (G64Track track in this.g64Tracks)
            {
                track.g64TrackOffset.SetStatusText(ref warningText, ref warningCount, ref errorText, ref errorCount);
                track.g64TrackSize.SetStatusText(ref warningText, ref warningCount, ref errorText, ref errorCount);
                track.g64TrackSpeed.SetStatusText(ref warningText, ref warningCount, ref errorText, ref errorCount);
                track.g64TrackSpeedOffset.SetStatusText(ref warningText, ref warningCount, ref errorText, ref errorCount);
                track.g64TrackGCRData.SetStatusText(ref warningText, ref warningCount, ref errorText, ref errorCount);
                track.g64TrackSpaceAfterGCRData.SetStatusText(ref warningText, ref warningCount, ref errorText, ref errorCount);
                track.g64TrackSpeedZoneData.SetStatusText(ref warningText, ref warningCount, ref errorText, ref errorCount);
            }
            if (fileName.Length > 55) { fileName = fileName.Substring(0, 55); }
            retText.AppendFormat("{0,-55}", fileName);
            if ((warningCount == 0) && (errorCount == 0))
            {
                retText.Append(" OK");
            }
            if (warningCount > 0)
            {
                retText.AppendFormat(" Warning:{0,3}", warningCount);
            }
            if (errorCount > 0)
            {
                retText.AppendFormat(" Error:{0,3}", errorCount);
            }
            retText.AppendLine();
            if (warningText.Length > 0)
            {
                retText.AppendLine("Warning:");
                retText.Append(warningText.ToString());
            }
            if (errorText.Length > 0)
            {
                retText.AppendLine("Error:");
                retText.Append(errorText.ToString());
            }
            return retText.ToString();
        }
        public void ShowInfo()
        {
            Console.WriteLine("Image Info:");
            Console.WriteLine(String.Format("File Signature    : {0}", this.g64FileSignature.ElementValue.ToString()));
            Console.WriteLine(String.Format("G64 Version       : {0}", this.g64Version.ElementValue.ToString()));
            Console.WriteLine(String.Format("Number of Tracks  : {0}", this.g64NumberOfTracks.ElementValue.ToString()));
            Console.WriteLine(String.Format("Size of Tracks    : {0}", this.g64SizeOfTracks.ElementValue.ToString()));
        }
        public void ShowTrackInfo()
        {
            Console.WriteLine("Track Info:");
            foreach (G64Track track in this.g64Tracks)
            {
                int syncCount = 0;
                int bitCount = 0;
                if (track.g64TrackGCRData != null)
                {
                    BitArray bits = new BitArray(track.g64TrackGCRData.ElementValue);
                    foreach (Boolean b in bits)
                    {
                        if (b)
                        {
                            bitCount++;
                        }
                        else
                        {
                            if (bitCount >= 20)
                            {
                                syncCount++;
                            }
                            bitCount = 0;
                        }
                    }
                }
                Console.WriteLine(String.Format("Track:{0,-4} Offset:{1:X6} Size:{2,-4} Sync Count:{3,-2} Speed:{4,-1} Speed Offset:{5:X6}"
                    , CBMFunction.CBMTrackNoByTrackNo(track.no)
                    , track.g64TrackOffset
                    , track.g64TrackSize.ToString()
                    , syncCount.ToString()
                    , track.g64TrackSpeed.ToString()
                    , track.g64TrackSpeedOffset
                ));
                if (track.g64TrackSpeedZoneData != null)
                {
                    Console.WriteLine(String.Concat(Array.ConvertAll((byte[])track.g64TrackSpeedZoneData.ElementValue, x => x.ToString("X2"))));
                }
            }
        }
        public void ShowAreaInfo()
        {
            Console.WriteLine("Area Info:");
            Int32 lastOffset = 0;
            List<G64AreaInfo> areaInfos = this.g64ImageData.GetAreaInfos();
            foreach (G64AreaInfo ai in areaInfos.OrderBy(o => o.StartOffset).ToList())
            {
                if (lastOffset < ai.StartOffset)
                {
                    Console.WriteLine(String.Format("----> gap warning between {0:X6} and {1:X6}", lastOffset, ai.StartOffset));
                }
                if (lastOffset > ai.StartOffset)
                {
                    Console.WriteLine(String.Format("----> areas injury"));
                }
                Console.WriteLine(String.Format("Offset:{0:X6} Length:{1,-8} {2}"
                    , ai.StartOffset
                    , ai.AreaLength
                    , ai.InfoText.ToString()
                    ));
                lastOffset = ai.StartOffset + ai.AreaLength;
            }
            if (lastOffset < this.g64ImageData.Length)
            {
                Console.WriteLine(String.Format("----> gap warning between {0:X6} and {1:X6}", lastOffset, this.g64ImageData.Length));
            }
            if (lastOffset > this.g64ImageData.Length)
            {
                Console.WriteLine(String.Format("----> areas injury"));
            }
        }
    }
}